Skip to main content

Asset Modules与资源文件处理

file-loader

在 JS 中,我们使用 import 引入的图片资源时,在 webpack 打包的时候需要借助 file-loader 来处理。file-loader 的作用就是帮助我们处理 import/require() 引入的文件资源,并且打包后会将它们一起放到打包文件中去。

另外,还有一个场景就是在样式文件中使用 background: url(xxx) 引入某个图片资源作为背景,file-loader 也可以对其处理。

首先安装 file-loader

$ npm i file-loader -D

然后在 webpack.config.js 添加如下配置。

{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
loader: "file-loader",
options: {
name: "img/[name].[hash:6].[ext]",
// outputPath: "img" // 可以这样用但是不建议
}
}
]
},

webpack 在打包过程中,如果发现某个 js 文件导入了一个图片资源文件,那么就会将该图片打包到 output 根目录下的 img 目录中。

这里的 [name].[hash:6].[ext] 是占位符,[name] 表示资源文件名,[hash:6] 表示取 6 位的哈希值,[ext] 表示文件的后缀名。

下面是几个常用的占位符。

占位符说明
[ext]被处理文件的扩展名
[name]被处理文件的文件名
[hash]被处理文件的内容,由 md4 算法处理,生成了 128 位的 hash 值 ( 32 个十六进制数)
[contentHash]对于 file-loader 来说和 [hash] 相同,但是在 webpack 的其他一些地方不一样,后面会讲到
[hash:\<length>]截取指定长度哈希值
[path]被处理文件相对于 webpack 配置文件的路径
important

如果我们不给 file-loader 传递 name 参数,那么在默认情况下打包后的图片资源文件名类似这个样子 615a7b44840a5feef178068b86dabb7d.png,底层使用了 md4 摘要算法,将资源中的内容提取出来转换成了 128 bit 位的哈希值,然后再转为十六进制,最终就成为了这样的文件名。

url-loader

url-loaderfile-loader 的工作方式相似,但是 url-loader 对于较小的文件,可以将其转成 base64 和 uri。

首先安装 url-loader

$ npm i url-loader -D

然后在 webpack.config.js 添加如下配置。

{
test: /\.(png|jpe?g|gif|svg)$/,
use: [
{
loader: "url-loader",
options: {
name: "img/[name].[hash:6].[ext]",
limit: 100 * 1024 // 100KB
}
}
]
}

可以向 url-loader 传递一个 limit 参数,这里以 100KB 为分界点,小于 100KB 的图片使用 base64,大于 100KB 的图片直接单独放一个文件夹。

图片存储优化
  • 对于较大的图片我们应该存放到单独的一个文件夹里面,可以先让页面中显示一部分
  • 对于较小的图片可以直接 base64,放到 js 文件中,以此来减少 http 请求次数

raw-loader

使用该 loader 可以允许导入一个外部文件,将其内容作为字符串使用。

详情参考 raw-loader

Asset Modules

在 webpack5 之前加载某些资源的时候需要使用一些 loader,比如:raw-loaderurl-loaderfile-loader,从 webpack5 开始,我们可以直接使用 资源模块类型 ( asset module type ),来替代这些 loader

资源模块类型说明
asset/resource作用可以类比于 file-loader
asset/inline作用可以类比于 url-loader,但只能生成内联资源(data uri)
asset综合上面两种类型的作用
asset/source导出资源的源代码,这个不常用
important

在 webpack5 之后,不再推荐使用其他 loader 来处理图片、字体等资源文件了,比如你使用 file-loader 来处理图片资源,很可能出现一些奇怪的问题。

asset/resource

作用和 file-loader 类似,无论是直接通过 import/require 导入图片资源,还是设置 background: url(xxx),webpack 在打包过程中都会将资源打包单独的目录下。

你需要在 webpack.config.js 中添加如下配置。

{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset/resource",
generator: {
filename: "img/[name].[hash:6][ext]"
}
}

asset/inline

作用和 url-loader 类似,但是需要注意的是无法设置 limit,无论多大的图片资源,最终都会被 base64,以 data uri 的方式进行内联。

你需要在 webpack.config.js 中添加如下配置。

{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset/inline"
}

asset

综合了 asset/resourceasset/inline 的效果,可以设置一个分界值,如果资源大小超过这个分界值,那么就将其打包到单独的目录,否则就以内联(data uri)的形式引入。

你需要在 webpack.config.js 中添加如下配置。

{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset",
generator: {
filename: "img/[name].[hash:6][ext]"
},
parser: {
dataUrlCondition: {
maxSize: 100 * 1024 // 超过 100KB 则单独打包出来
}
}
}

asset/source

可以在项目中导入某个文件,将其内容作为字符串使用,作用和 raw-loader 类似。

比如,你在 webpack.config.js 中添加了如下配置。

{
test: /\.txt/,
type: "asset/source"
}

那么你就可以在 js 中直接导入一个 txt 文本文件,将其内容作为字符串使用。

import text from "./hello.txt";

const s = text; // 文件中的内容